#pragma once

#include <AVUIDependencyProperty.h>
#include <AVUIThickness.h>

#pragma push_macro("GetNextSibling")
#undef GetNextSibling

namespace AVUI {

class DependencyObject;
class Visual;
class UIElement;
class Point;
class Adorner;
class KeyboardFocusChangedEventArgs;
class TraversalRequest;

class KeyboardNavigation : public Object
{
	friend class UIElement;
    friend class FrameworkElement;
public:

    KeyboardNavigation() { }
    DECLARE_ELEMENT(KeyboardNavigation, Object);

    DECLARE_DEPENDENCY_PROPERTY(TabIndex);
    DECLARE_DEPENDENCY_PROPERTY(IsTabStop);
    DECLARE_DEPENDENCY_PROPERTY(AcceptsReturn);
    DECLARE_DEPENDENCY_PROPERTY(DirectionalNavigationMargin);
    DECLARE_DEPENDENCY_PROPERTY(TabNavigation);
    DECLARE_DEPENDENCY_PROPERTY(DirectionalNavigation);

    UIElement* PredictFocusedElement(UIElement* pSource, FocusNavigationDirection::Enum direction);

    static KeyboardNavigation* get_Current();

    static FocusNavigationDirection::Enum KeyToTraversalDirection(Key::Enum key);

    bool Navigate(DependencyObject* pCurrentElement, TraversalRequest* pRequest);
    static bool IsKeyboardMostRecentInputDevice();

    static void ShowFocusVisual();

private:
    static void StaticConstructor();

    void ShowFocusVisual(DependencyObject* pElement); 

    void HideFocusVisual();
	bool get_AlwaysShowFocusVisual() { return true; }

    bool Navigate(UIElement* pCurrentElement, FocusNavigationDirection::Enum request, ModifierKeys::Enum modifierKeys);
    bool Navigate(UIElement* pCurrentElement, FocusNavigationDirection::Enum request, ModifierKeys::Enum modifierKeys, UIElement* pFirstElement);

    static Visual* GetVisualRoot(DependencyObject* pDO);

    UIElement* GetNextTab(UIElement* pDO, UIElement* pContainer, bool goDownOnly);
    UIElement* GetPrevTab(UIElement* pDO, UIElement* pContainer, bool goDownOnly);
    UIElement* GetGroupParent(UIElement* pDO, bool includeCurrent = false);
    UIElement* GetNextInDirection(UIElement* pDO, FocusNavigationDirection::Enum direction);

    UIElement* MoveNext(UIElement* pDO, UIElement* pContainer, FocusNavigationDirection::Enum direction, float startRange, float endRange);

    bool IsEndlessLoop(UIElement* pSource, UIElement* pContainer);
    bool IsTabStop(UIElement* pDO);
    bool IsGroup(UIElement* pDO);
    void ResetBaseLines(float value, bool horizontalDirection);
    float GetDistance(const Point& ptFrom, const Point& ptTo);
    float GetDistance(const Rect& rectFrom, const Rect& rectTo, FocusNavigationDirection::Enum direction);
    bool IsInDirection(const Rect& rectFrom, const Rect& rectTo, FocusNavigationDirection::Enum direction);
    bool IsInRange(UIElement* pSource, UIElement* pTarget, const Rect& sourceRect, const Rect& targetRect, FocusNavigationDirection::Enum direction, float startRange, float endRange);
    float GetPerpDistance(const Rect& sourceRect, const Rect& targetRect, FocusNavigationDirection::Enum direction);
    UIElement* GetFirstChild(UIElement* pParent);
    UIElement* GetNextSibling(UIElement* pParent);
    UIElement* GetParent(UIElement* pUIE);
    void UpdateActiveElement(DependencyObject* pActiveElement) { } // TODO -- 
    void NotifyFocusChanged(Object* pSender, KeyboardFocusChangedEventArgs* e) { } // TODO -- 
    static void UpdateFocusedElement(DependencyObject* pFocusTarget);

 

 


 


    KeyboardNavigationMode::Enum GetKeyNavigationMode(UIElement* pDO);
    Rect GetRectangle(UIElement* pDO);
    UIElement* FindNextInDirection(UIElement* pSource, const Rect& sourceRect, UIElement* pContainer, FocusNavigationDirection::Enum direction, float startRange, float endRange);
    UIElement* GetNextInTree(UIElement* pSource, UIElement* pContainer);
    

    DependencyProperty* m_pNavigationProperty;
    float m_verticalBaseline;
    float m_horizontalBaseline;

	TRefCountedPtr<Adorner> m_pFocusVisualAdornerCache;
};

}; // namespace AVUI

#pragma pop_macro("GetNextSibling")




